﻿// // ******************************************************************
// //       /\ /|       @file       VideoListHelper.cs
// //       \ V/        @brief      await29
// //       | "")       @author     Await, 285283010@qq.com
// //       /  |
// //      /  \\        @Modified   2025-03-02 14:03
// //    *(__\_\        @Copyright  Copyright (c) , 2025-01-03 19:01 Await
// // ******************************************************************

using System.Collections.Concurrent;
using AutomaticSubtitles.Service.DataAccess.Model;

namespace AutomaticSubtitles.Service.Infrastructure.Helper;

public class VideoListHelper(ILogger<VideoListHelper> logger)
{
    /// <summary>
    /// 媒体数据扫描
    /// </summary>
    /// <param name="moviePath"></param>
    /// <param name="seriesPath"></param>
    /// <param name="noSubPath"></param>
    /// <returns></returns>
    public async Task<NormalScanVideoResult> RefreshMainListAsync(List<string>? moviePath, List<string>? seriesPath, List<string>? noSubPath = null)
    {
        logger.LogInformation("扫描普通电影和连续剧 开始...");
        // ------------------------------------------------------------------------------
        // 由于需要进行视频信息的缓存，用于后续的逻辑，那么本地视频的扫描默认都会进行
        var normalScanResult = new NormalScanVideoResult();
        //剔除空目录 noSubPath
        noSubPath = noSubPath?.Where(x => !string.IsNullOrWhiteSpace(x))?.ToList();

        // 直接由本程序自己去扫描视频视频有哪些
        // 全扫描
        var tasks = new List<Task>();
        if (moviePath != null)
            tasks.Add(Task.Run(async () =>
            {
                // --------------------------------------------------
                // 电影
                normalScanResult.MoviesDirMap = await SeriesHelper.MatchedVideoFileFromDirsAsync(logger, moviePath, noSubPath);
            }));
        if (seriesPath != null)
            tasks.Add(Task.Run(async () =>
            {
                // --------------------------------------------------
                // 连续剧
                // 遍历连续剧总目录下的第一层目录
                normalScanResult.SeriesDirMap = await SeriesHelper.GetSeriesListFromDirsAsync(logger, seriesPath, noSubPath);
            }));

        await Task.WhenAll(tasks);
        logger.LogInformation("扫描普通电影和连续剧 结束");
        return normalScanResult;
    }

    /// <summary>
    /// 字幕数据提取
    /// </summary>
    /// <param name="mediae"></param>
    /// <param name="wantedExts">true,是否强制提取</param>
    /// <param name="isMovie">是否电影</param>
    /// <param name="isAll">是否全部记录</param>
    /// <returns></returns>
    public static async Task<List<Auto_Subtitle>?> ObtainVideoSubtitleFiles(List<Auto_Media> mediae, Dictionary<string, bool> wantedExts, bool isMovie = true, bool isAll = false)
    {
        var data = new ConcurrentBag<Auto_Subtitle>();


        if (isMovie)
        {
            foreach (var item in mediae)
            {
                var subs = await SeriesHelper.GetMovieSubtitleFiles(item.Id, item.Path, wantedExts, isAll);
                if (subs is not { Count: > 0 }) continue;
                foreach (var citem in subs)
                    data.Add(citem);
            }

            return data.ToList();
        }

        var tvPlays = mediae.Where(x => x.Leve == 0);
        var tasks = tvPlays.Select(item => Task.Run(async () =>
            {
                var subs = await SeriesHelper.GetTvDramasSubtitleFiles(mediae.Where(x => x.ParentLevelId == item.Id).Select(x => (x.Id, x.Path)).ToList(), wantedExts,
                    isAll);
                if (subs is not { Count: > 0 }) return;
                foreach (var citem in subs)
                    data.Add(citem);
            }
        ));
        await Parallel.ForEachAsync(tasks, new ParallelOptions
        {
            MaxDegreeOfParallelism = 2
        }, async (task, _) => await task);
        // await Task.WhenAll(tasks);
        return data.ToList();
    }

    /// <summary>
    /// 获取默认缓存路径
    /// </summary>
    /// <param name="isMove"></param>
    /// <returns></returns>
    public static string GetCachePath(bool isMove)
    {
        return Common.GlobalPath + (isMove ? "Film" : "TVPlay");
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="isMove">是否电影</param>
    /// <param name="data">字幕数据</param>
    /// <returns></returns>
    public static async Task<(string?, bool, Auto_Subtitle)?> ObtainMediaSubtitles(bool isMove, Auto_Subtitle data, CancellationTokenSource? source = null)
    {
        var subPath = data.Path;
        source ??= new CancellationTokenSource();
        /**
         * 1.判断文件是否是字幕文件
         * 2.判断文件是否存在本地
         * 3.判断文件是否是缓存文件
         * 4.如果是缓存文件，直接返回缓存地址
         * 5.如果没有文件，调用下一个方法直接提取媒体中的字幕文件，转换成文件再返回文件，并修改此次操作
         */
        //
        // 判断文件是否是字幕文件
        // if (VideoFileUtils.IsWantedVideoExtDef(subPath))
        if (VideoFileUtils.IsSubExtWanted(Path.GetExtension(subPath)))
        {
            // 判断文件是否是缓存文件
            if (subPath.Contains(".cache"))
            {
                subPath = subPath.Replace(".cache", "");
                // 分割最后三个中的前两个
                var split = subPath.Split(".", 3);
                if (split.Length < 3) return null;
                subPath = $"{split[0]}.{split[1]}.{split[2]}";
            }

            // 判断文件是否存在本地
            if (File.Exists(subPath)) return (subPath, false, data);
            // 这里需要进行字幕文件的提取
        }

        //这里需要进行字幕文件的提取
        // 获取视频文件的元数据
        var mediaInfo = await VideoFileUtils.ObtainMediaInformation(subPath, source);
        // 获取视频文件的元数据
        if (mediaInfo == null) return (subPath, false, data);
        var subtitleStream = mediaInfo.SubtitleStreams.FirstOrDefault(x => x.Language == data.Language && x.Index == data.Index) ?? mediaInfo.SubtitleStreams.FirstOrDefault();
        if (subtitleStream is null) return null;
        var globalPath = GetCachePath(isMove);
        Console.WriteLine($@"长度:{mediaInfo.SubtitleStreams?.Count() ?? 0} 字幕流.{subPath}");
        if (!Directory.Exists(globalPath)) Directory.CreateDirectory(globalPath);
        var outputFilePath = $"{globalPath}/{Path.GetFileName(subPath).Replace(Path.GetExtension(subPath), "")}";
        var result = await VideoFileUtils.ObtainMediaSubtitles(subtitleStream, outputFilePath, subPath, source);
        if (result == null) return null;
        data.Path = result.Value.Item2;
        data.Language = subtitleStream.Language;
        data.Index = subtitleStream.Index;
        return (result.Value.Item2, true, data);
    }
}